1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package com.sun.java.util.jar.pack;
27
28 import java.io.ByteArrayOutputStream;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.io.OutputStream;
32 import java.util.Arrays;
33 import java.util.HashSet;
34 import java.util.Set;
35 import static com.sun.java.util.jar.pack.Constants.*;
36
37
38
39
40
41
42
43 class PopulationCoding implements CodingMethod {
44 Histogram vHist;
45 int[] fValues;
46 int fVlen;
47 long[] symtab;
48
49 CodingMethod favoredCoding;
50 CodingMethod tokenCoding;
51 CodingMethod unfavoredCoding;
52
53 int L = -1;
54
55 public void setFavoredValues(int[] fValues, int fVlen) {
56
57
58 assert(fValues[0] == 0);
59 assert(this.fValues == null);
60 this.fValues = fValues;
61 this.fVlen = fVlen;
62 if (L >= 0) {
63 setL(L);
64 }
65 }
66 public void setFavoredValues(int[] fValues) {
67 int lfVlen = fValues.length-1;
68 setFavoredValues(fValues, lfVlen);
69 }
70 public void setHistogram(Histogram vHist) {
71 this.vHist = vHist;
72 }
73 public void setL(int L) {
74 this.L = L;
75 if (L >= 0 && fValues != null && tokenCoding == null) {
76 tokenCoding = fitTokenCoding(fVlen, L);
77 assert(tokenCoding != null);
78 }
79 }
80
81 public static Coding fitTokenCoding(int fVlen, int L) {
82
83 if (fVlen < 256)
84
85 return BandStructure.BYTE1;
86 Coding longest = BandStructure.UNSIGNED5.setL(L);
87 if (!longest.canRepresentUnsigned(fVlen))
88 return null;
89 Coding tc = longest;
90 for (Coding shorter = longest; ; ) {
91 shorter = shorter.setB(shorter.B()-1);
92 if (shorter.umax() < fVlen)
93 break;
94 tc = shorter;
95 }
96 return tc;
97 }
98
99 public void setFavoredCoding(CodingMethod favoredCoding) {
100 this.favoredCoding = favoredCoding;
101 }
102 public void setTokenCoding(CodingMethod tokenCoding) {
103 this.tokenCoding = tokenCoding;
104 this.L = -1;
105 if (tokenCoding instanceof Coding && fValues != null) {
106 Coding tc = (Coding) tokenCoding;
107 if (tc == fitTokenCoding(fVlen, tc.L()))
108 this.L = tc.L();
109
110 }
111 }
112 public void setUnfavoredCoding(CodingMethod unfavoredCoding) {
113 this.unfavoredCoding = unfavoredCoding;
114 }
115
116 public int favoredValueMaxLength() {
117 if (L == 0)
118 return Integer.MAX_VALUE;
119 else
120 return BandStructure.UNSIGNED5.setL(L).umax();
121 }
122
123 public void resortFavoredValues() {
124 Coding tc = (Coding) tokenCoding;
125
126 fValues = BandStructure.realloc(fValues, 1+fVlen);
127
128 int fillp = 1;
129 for (int n = 1; n <= tc.B(); n++) {
130 int nmax = tc.byteMax(n);
131 if (nmax > fVlen)
132 nmax = fVlen;
133 if (nmax < tc.byteMin(n))
134 break;
135 int low = fillp;
136 int high = nmax+1;
137 if (high == low) continue;
138 assert(high > low)
139 : high+"!>"+low;
140 assert(tc.getLength(low) == n)
141 : n+" != len("+(low)+") == "+
142 tc.getLength(low);
143 assert(tc.getLength(high-1) == n)
144 : n+" != len("+(high-1)+") == "+
145 tc.getLength(high-1);
146 int midTarget = low + (high-low)/2;
147 int mid = low;
148
149 int prevCount = -1;
150 int prevLimit = low;
151 for (int i = low; i < high; i++) {
152 int val = fValues[i];
153 int count = vHist.getFrequency(val);
154 if (prevCount != count) {
155 if (n == 1) {
156
157
158 Arrays.sort(fValues, prevLimit, i);
159 } else if (Math.abs(mid - midTarget) >
160 Math.abs(i - midTarget)) {
161
162
163 mid = i;
164 }
165 prevCount = count;
166 prevLimit = i;
167 }
168 }
169 if (n == 1) {
170 Arrays.sort(fValues, prevLimit, high);
171 } else {
172
173 Arrays.sort(fValues, low, mid);
174 Arrays.sort(fValues, mid, high);
175 }
176 assert(tc.getLength(low) == tc.getLength(mid));
177 assert(tc.getLength(low) == tc.getLength(high-1));
178 fillp = nmax+1;
179 }
180 assert(fillp == fValues.length);
181
182
183 symtab = null;
184 }
185
186 public int getToken(int value) {
187 if (symtab == null)
188 symtab = makeSymtab();
189 int pos = Arrays.binarySearch(symtab, (long)value << 32);
190 if (pos < 0) pos = -pos-1;
191 if (pos < symtab.length && value == (int)(symtab[pos] >>> 32))
192 return (int)symtab[pos];
193 else
194 return 0;
195 }
196
197 public int[][] encodeValues(int[] values, int start, int end) {
198
199 int[] tokens = new int[end-start];
200 int nuv = 0;
201 for (int i = 0; i < tokens.length; i++) {
202 int val = values[start+i];
203 int tok = getToken(val);
204 if (tok != 0)
205 tokens[i] = tok;
206 else
207 nuv += 1;
208 }
209
210 int[] unfavoredValues = new int[nuv];
211 nuv = 0;
212 for (int i = 0; i < tokens.length; i++) {
213 if (tokens[i] != 0) continue;
214 int val = values[start+i];
215 unfavoredValues[nuv++] = val;
216 }
217 assert(nuv == unfavoredValues.length);
218 return new int[][]{ tokens, unfavoredValues };
219 }
220
221 private long[] makeSymtab() {
222 long[] lsymtab = new long[fVlen];
223 for (int token = 1; token <= fVlen; token++) {
224 lsymtab[token-1] = ((long)fValues[token] << 32) | token;
225 }
226
227 Arrays.sort(lsymtab);
228 return lsymtab;
229 }
230
231 private Coding getTailCoding(CodingMethod c) {
232 while (c instanceof AdaptiveCoding)
233 c = ((AdaptiveCoding)c).tailCoding;
234 return (Coding) c;
235 }
236
237
238 public void writeArrayTo(OutputStream out, int[] a, int start, int end) throws IOException {
239 int[][] vals = encodeValues(a, start, end);
240 writeSequencesTo(out, vals[0], vals[1]);
241 }
242 void writeSequencesTo(OutputStream out, int[] tokens, int[] uValues) throws IOException {
243 favoredCoding.writeArrayTo(out, fValues, 1, 1+fVlen);
244 getTailCoding(favoredCoding).writeTo(out, computeSentinelValue());
245 tokenCoding.writeArrayTo(out, tokens, 0, tokens.length);
246 if (uValues.length > 0)
247 unfavoredCoding.writeArrayTo(out, uValues, 0, uValues.length);
248 }
249
250 int computeSentinelValue() {
251 Coding fc = getTailCoding(favoredCoding);
252 if (fc.isDelta()) {
253
254 return 0;
255 } else {
256
257 int min = fValues[1];
258 int last = min;
259
260 for (int i = 2; i <= fVlen; i++) {
261 last = fValues[i];
262 min = moreCentral(min, last);
263 }
264 int endVal;
265 if (fc.getLength(min) <= fc.getLength(last))
266 return min;
267 else
268 return last;
269 }
270 }
271
272 public void readArrayFrom(InputStream in, int[] a, int start, int end) throws IOException {
273
274 setFavoredValues(readFavoredValuesFrom(in, end-start));
275
276 tokenCoding.readArrayFrom(in, a, start, end);
277
278 int headp = 0, tailp = -1;
279 int uVlen = 0;
280 for (int i = start; i < end; i++) {
281 int tok = a[i];
282 if (tok == 0) {
283
284 if (tailp < 0) {
285 headp = i;
286 } else {
287 a[tailp] = i;
288 }
289 tailp = i;
290 uVlen += 1;
291 } else {
292 a[i] = fValues[tok];
293 }
294 }
295
296 int[] uValues = new int[uVlen];
297 if (uVlen > 0)
298 unfavoredCoding.readArrayFrom(in, uValues, 0, uVlen);
299 for (int i = 0; i < uVlen; i++) {
300 int nextp = a[headp];
301 a[headp] = uValues[i];
302 headp = nextp;
303 }
304 }
305
306 int[] readFavoredValuesFrom(InputStream in, int maxForDebug) throws IOException {
307 int[] lfValues = new int[1000];
308
309
310
311 Set<Integer> uniqueValuesForDebug = null;
312 assert((uniqueValuesForDebug = new HashSet<>()) != null);
313 int fillp = 1;
314 maxForDebug += fillp;
315 int min = Integer.MIN_VALUE;
316
317 int last = 0;
318 CodingMethod fcm = favoredCoding;
319 while (fcm instanceof AdaptiveCoding) {
320 AdaptiveCoding ac = (AdaptiveCoding) fcm;
321 int len = ac.headLength;
322 while (fillp + len > lfValues.length) {
323 lfValues = BandStructure.realloc(lfValues);
324 }
325 int newFillp = fillp + len;
326 ac.headCoding.readArrayFrom(in, lfValues, fillp, newFillp);
327 while (fillp < newFillp) {
328 int val = lfValues[fillp++];
329 assert(uniqueValuesForDebug.add(val));
330 assert(fillp <= maxForDebug);
331 last = val;
332 min = moreCentral(min, val);
333
334 }
335 fcm = ac.tailCoding;
336 }
337 Coding fc = (Coding) fcm;
338 if (fc.isDelta()) {
339 for (long state = 0;;) {
340
341 state += fc.readFrom(in);
342 int val;
343 if (fc.isSubrange())
344 val = fc.reduceToUnsignedRange(state);
345 else
346 val = (int)state;
347 state = val;
348 if (fillp > 1 && (val == last || val == min))
349 break;
350 if (fillp == lfValues.length)
351 lfValues = BandStructure.realloc(lfValues);
352 lfValues[fillp++] = val;
353 assert(uniqueValuesForDebug.add(val));
354 assert(fillp <= maxForDebug);
355 last = val;
356 min = moreCentral(min, val);
357
358 }
359 } else {
360 for (;;) {
361 int val = fc.readFrom(in);
362 if (fillp > 1 && (val == last || val == min))
363 break;
364 if (fillp == lfValues.length)
365 lfValues = BandStructure.realloc(lfValues);
366 lfValues[fillp++] = val;
367 assert(uniqueValuesForDebug.add(val));
368 assert(fillp <= maxForDebug);
369 last = val;
370 min = moreCentral(min, val);
371
372 }
373 }
374 return BandStructure.realloc(lfValues, fillp);
375 }
376
377 private static int moreCentral(int x, int y) {
378 int kx = (x >> 31) ^ (x << 1);
379 int ky = (y >> 31) ^ (y << 1);
380
381 kx -= Integer.MIN_VALUE;
382 ky -= Integer.MIN_VALUE;
383 int xy = (kx < ky? x: y);
384
385 assert(xy == moreCentralSlow(x, y));
386 return xy;
387 }
388
389
390
391
392
393
394
395
396 private static int moreCentralSlow(int x, int y) {
397 int ax = x;
398 if (ax < 0) ax = -ax;
399 if (ax < 0) return y;
400 int ay = y;
401 if (ay < 0) ay = -ay;
402 if (ay < 0) return x;
403 if (ax < ay) return x;
404 if (ax > ay) return y;
405
406 return x < y ? x : y;
407 }
408
409 static final int[] LValuesCoded
410 = { -1, 4, 8, 16, 32, 64, 128, 192, 224, 240, 248, 252 };
411
412 public byte[] getMetaCoding(Coding dflt) {
413 int K = fVlen;
414 int LCoded = 0;
415 if (tokenCoding instanceof Coding) {
416 Coding tc = (Coding) tokenCoding;
417 if (tc.B() == 1) {
418 LCoded = 1;
419 } else if (L >= 0) {
420 assert(L == tc.L());
421 for (int i = 1; i < LValuesCoded.length; i++) {
422 if (LValuesCoded[i] == L) { LCoded = i; break; }
423 }
424 }
425 }
426 CodingMethod tokenDflt = null;
427 if (LCoded != 0 && tokenCoding == fitTokenCoding(fVlen, L)) {
428
429 tokenDflt = tokenCoding;
430 }
431 int FDef = (favoredCoding == dflt)?1:0;
432 int UDef = (unfavoredCoding == dflt || unfavoredCoding == null)?1:0;
433 int TDef = (tokenCoding == tokenDflt)?1:0;
434 int TDefL = (TDef == 1) ? LCoded : 0;
435 assert(TDef == ((TDefL>0)?1:0));
436 ByteArrayOutputStream bytes = new ByteArrayOutputStream(10);
437 bytes.write(_meta_pop + FDef + 2*UDef + 4*TDefL);
438 try {
439 if (FDef == 0) bytes.write(favoredCoding.getMetaCoding(dflt));
440 if (TDef == 0) bytes.write(tokenCoding.getMetaCoding(dflt));
441 if (UDef == 0) bytes.write(unfavoredCoding.getMetaCoding(dflt));
442 } catch (IOException ee) {
443 throw new RuntimeException(ee);
444 }
445 return bytes.toByteArray();
446 }
447 public static int parseMetaCoding(byte[] bytes, int pos, Coding dflt, CodingMethod res[]) {
448 int op = bytes[pos++] & 0xFF;
449 if (op < _meta_pop || op >= _meta_limit) return pos-1;
450 op -= _meta_pop;
451 int FDef = op % 2;
452 int UDef = (op / 2) % 2;
453 int TDefL = (op / 4);
454 int TDef = (TDefL > 0)?1:0;
455 int L = LValuesCoded[TDefL];
456 CodingMethod[] FCode = {dflt}, TCode = {null}, UCode = {dflt};
457 if (FDef == 0)
458 pos = BandStructure.parseMetaCoding(bytes, pos, dflt, FCode);
459 if (TDef == 0)
460 pos = BandStructure.parseMetaCoding(bytes, pos, dflt, TCode);
461 if (UDef == 0)
462 pos = BandStructure.parseMetaCoding(bytes, pos, dflt, UCode);
463 PopulationCoding pop = new PopulationCoding();
464 pop.L = L;
465 pop.favoredCoding = FCode[0];
466 pop.tokenCoding = TCode[0];
467 pop.unfavoredCoding = UCode[0];
468 res[0] = pop;
469 return pos;
470 }
471
472 private String keyString(CodingMethod m) {
473 if (m instanceof Coding)
474 return ((Coding)m).keyString();
475 if (m == null)
476 return "none";
477 return m.toString();
478 }
479 public String toString() {
480 PropMap p200 = Utils.currentPropMap();
481 boolean verbose
482 = (p200 != null &&
483 p200.getBoolean(Utils.COM_PREFIX+"verbose.pop"));
484 StringBuilder res = new StringBuilder(100);
485 res.append("pop(").append("fVlen=").append(fVlen);
486 if (verbose && fValues != null) {
487 res.append(" fV=[");
488 for (int i = 1; i <= fVlen; i++) {
489 res.append(i==1?"":",").append(fValues[i]);
490 }
491 res.append(";").append(computeSentinelValue());
492 res.append("]");
493 }
494 res.append(" fc=").append(keyString(favoredCoding));
495 res.append(" tc=").append(keyString(tokenCoding));
496 res.append(" uc=").append(keyString(unfavoredCoding));
497 res.append(")");
498 return res.toString();
499 }
500 }